package com.ccc.boot.redis.config;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import com.ccc.boot.redis.config.MyRedisCacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
 * Redis缓存配置
 *
 * @author superC
 * @version 0.1.0
 * @date 2022/4/8
 */

@Configuration
//开启缓存
@EnableCaching
public class MyRedisCacheConfiguration extends CachingConfigurerSupport {
    protected static final Logger logger = LoggerFactory.getLogger(MyRedisCacheConfiguration.class);

    /**
     * 默认过期时间设置为7天
     */
    private Duration DEFAULT_TIME_EXPIRE = Duration.ofDays(7);

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){

        /**
         *  序列化
         *      创建FastJson对象，替换默认序列化
         */
        GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();


        /**
         *  配置序列化
         *      设置缓存的默认过期时间，也是使用Duration设置。框架默认过期时间设置为一天
         *      解决乱码的问题
         *      不缓存空值
         */
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(DEFAULT_TIME_EXPIRE)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer))
                .disableCachingNullValues();

        /**
         *  创建RedisCacheManage对象，将上面的配置导入
         */
//        RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
//                .cacheDefaults(config)
//                .build();

        /**
         * 创建自定义RedisCacheManage对象，
         */
        MyRedisCacheManager redisCacheManager = new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), config);

        return redisCacheManager;
    }

    /**
     * @author superC
     * @description 自定义缓存异常处理(使用注解方式时，redis出现异常后会触发)
     * @date 2020/11/4 11:30
     */
    @Override
    public CacheErrorHandler errorHandler(){
        CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                logger.error("【捕获Redis异常】\r\n key={}\r\n异常记录：", key, exception);
            }

            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
                logger.error("【捕获Redis异常】\r\n key={}\r\n异常记录：", key, exception);
            }

            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
                logger.error("【捕获Redis异常】\r\n 异常记录：", exception);
            }

            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) {
                logger.error("【捕获Redis异常】\r\n 异常记录：", exception);
            }
        };
        return cacheErrorHandler;
    }

}
